﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using ReagentStore.BLL;
using ReagentStore.ERM;
using ReagentStore.PRT;
using ReagentStore.Properties;
using ReagentStore.Report;
using ReagentStore.Resources.Properties;
using ReagentStore.UTL;

namespace ReagentStore
{
	public partial class MainForm : Form
	{
		private readonly Presentation _presentation = Presentation.CreateInstance();

		public MainForm()
		{
			InitializeComponent();
			InitializeImageList();
			InitializeToolbar();
		}

		private void InitializeTreeRoot()
		{
			_nodeRoot.ContextMenuStrip = ctxmenuRoot;
		}

		private void InitializeImageList()
		{
			imageList.Images.Add(DefaultResources.iconIncoming);
			imageList.Images.Add(DefaultResources.iconOutgoing);
			imageList.Images.Add(DefaultResources.iconWear);
			imageList.Images.Add(DefaultResources.iconPurchase);
			imageList.Images.Add(DefaultResources.iconExpiration);
			imageList.Images.Add(DefaultResources.iconRecord);
			imageList.Images.Add(DefaultResources.iconStock);
			imageList.Images.Add(DefaultResources.iconExit);
		}

		private void InitializeToolbar()
		{
			toolbarMain.ImageList = imageList;
			for (int idx = 0, img = 0; idx < toolbarMain.Items.Count && img < imageList.Images.Count; idx++)
			{
				ToolStripItem control = toolbarMain.Items[idx];
				if (!(control is ToolStripButton))
					continue;

				control.ImageIndex = img;
				img++;
			}
		}

		private void InitializeEventProxy()
		{
			_presentation.CatalogEventProxy.Attach(BuildTreeViewCatalog);
			_presentation.ReagentEventProxy.Attach(BuildLabelReagent);
			_presentation.ReagentEventProxy.Attach(InsertReagentsIntoTreeView);
			_presentation.ProductEventProxy.Attach(BuildListViewProduct);
			_presentation.ProductEventProxy.Attach(BuildLabelProduct);
			_presentation.RecordEventProxy.Attach(BuildListViewRecord);
			_presentation.MessageProxy.Attach(ShowMessage);
		}

		private void ShowMessage(object sender, EntityEventArgs e)
		{
			MessageBox.Show(this, e.Argument.ToString(), "提示", MessageBoxButtons.OK);
		}

		private object GetSelectedObjectTag(Control control)
		{
			object result = null;
			switch (control.GetType().Name)
			{
				case "TreeView":
					var tree = (TreeView) control;
					TreeNode node = tree.SelectedNode;
					if (node != null)
						result = tree.SelectedNode.Tag;
					break;

				case "ListView":
					var listview = (ListView) control;
					if (listview.SelectedItems.Count > 0)
						result = listview.SelectedItems[0].Tag;
					break;

				case "ContextMenuStrip":
					var menu = (ContextMenuStrip) control;
					Control source = menu.SourceControl;
					switch (source.GetType().Name)
					{
						case "TreeView":
							var mtree = (TreeView) source;
							TreeNode mnode = mtree.GetNodeAt(mtree.PointToClient(menu.Location));
							if (mnode != null)
								result = mnode.Tag;
							break;

						case "ListView":
							var mlistview = (ListView) source;
							Point mpos = mlistview.PointToClient(menu.Location);
							ListViewItem mitem = mlistview.GetItemAt(mpos.X, mpos.Y);
							if (mitem != null)
								result = mitem.Tag;
							break;
					}
					break;
			}
			return result;
		}

		private void menuCatalogInsert_Click(object sender, EventArgs e)
		{
			Catalog catalog = Catalog.CreateCatalog(default(int), string.Empty);
			using (var dlg = new CatalogDialog(new DialogParam<Catalog>(ActionTypes.Insert, catalog), InsertCatalog))
				dlg.ShowDialog();
		}

		private void InsertCatalog(DialogParam<Catalog> param)
		{
			_presentation.InsertCatalog(param.Parameter);
		}

		private void ctxmenuCatalogInsert_Click(object sender, EventArgs e)
		{
			menuCatalogInsert_Click(sender, e);
		}

		private void ctxmenuCatalogUpdate_Click(object sender, EventArgs e)
		{
			var catalog = GetSelectedObjectTag(ctxmenuCatalog) as Catalog;
			if (catalog == null)
				return;

			using (var dlg = new CatalogDialog(new DialogParam<Catalog>(ActionTypes.Update, catalog), UpdateCatalog))
				dlg.ShowDialog();
		}

		private void menuCatalogUpdate_Click(object sender, EventArgs e)
		{
			var catalog = GetSelectedObjectTag(treeviewCatalog) as Catalog;
			if (catalog == null)
				return;

			using (var dlg = new CatalogDialog(new DialogParam<Catalog>(ActionTypes.Update, catalog), UpdateCatalog))
				dlg.ShowDialog();
		}

		private void UpdateCatalog(DialogParam<Catalog> param)
		{
			_presentation.UpdateCatalog(param.Parameter);
		}

		private void ctxmenuCatalogDelete_Click(object sender, EventArgs e)
		{
			var catalog = GetSelectedObjectTag(ctxmenuCatalog) as Catalog;
			if (catalog == null)
				return;

			using (var dlg = new CatalogDialog(new DialogParam<Catalog>(ActionTypes.Delete, catalog), DeleteCatalog))
				dlg.ShowDialog();
		}

		private void menuCatalogDelete_Click(object sender, EventArgs e)
		{
			var catalog = GetSelectedObjectTag(treeviewCatalog) as Catalog;
			if (catalog == null)
				return;

			using (var dlg = new CatalogDialog(new DialogParam<Catalog>(ActionTypes.Delete, catalog), DeleteCatalog))
				dlg.ShowDialog();
		}

		private void DeleteCatalog(DialogParam<Catalog> param)
		{
			_presentation.DeleteCatalog(param.Parameter);
		}

		private void ctxmenuReagentInsert_Click(object sender, EventArgs e)
		{
			var catalog = GetSelectedObjectTag(ctxmenuCatalog) as Catalog;
			if (catalog == null)
				return;

			Reagent reagent = Reagent.CreateReagent(default(int), string.Empty, string.Empty, 0, 0, 0, catalog.CatalogID);
			using (var dlg = new ReagentDialog(new DialogParam<Reagent>(ActionTypes.Insert, reagent), InsertReagent))
				dlg.ShowDialog();
		}

		private void menuReagentInsert_Click(object sender, EventArgs e)
		{
			Reagent reagent = Reagent.CreateReagent(default(int), string.Empty, string.Empty, 0, 0, 0, default(int));
			using (var dlg = new ReagentDialog(new DialogParam<Reagent>(ActionTypes.Insert, reagent), InsertReagent))
				dlg.ShowDialog();
		}

		private void InsertReagent(DialogParam<Reagent> param)
		{
			_presentation.InsertReagent(param.Parameter);
		}

		private void ctxmenuReagentUpdate_Click(object sender, EventArgs e)
		{
			var reagent = GetSelectedObjectTag(ctxmenuReagent) as Reagent;
			if (reagent == null)
				return;

			using (var dlg = new ReagentDialog(new DialogParam<Reagent>(ActionTypes.Update, reagent), UpdateReagent))
				dlg.ShowDialog();
		}

		private void menuReagentUpdate_Click(object sender, EventArgs e)
		{
			var reagent = GetSelectedObjectTag(treeviewCatalog) as Reagent;
			if (reagent == null)
				return;

			using (var dlg = new ReagentDialog(new DialogParam<Reagent>(ActionTypes.Update, reagent), UpdateReagent))
				dlg.ShowDialog();
		}

		private void UpdateReagent(DialogParam<Reagent> param)
		{
			_presentation.UpdateReagent(param.Parameter);
		}

		private void menuReagentDelete_Click(object sender, EventArgs e)
		{
			var reagent = GetSelectedObjectTag(treeviewCatalog) as Reagent;
			if (reagent == null)
				return;

			using (var dlg = new ReagentDialog(new DialogParam<Reagent>(ActionTypes.Delete, reagent), DeleteReagent))
				dlg.ShowDialog();
		}

		private void ctxmenuReagentDelete_Click(object sender, EventArgs e)
		{
			var reagent = GetSelectedObjectTag(ctxmenuReagent) as Reagent;
			if (reagent == null)
				return;

			using (var dlg = new ReagentDialog(new DialogParam<Reagent>(ActionTypes.Delete, reagent), DeleteReagent))
				dlg.ShowDialog();
		}

		private void DeleteReagent(DialogParam<Reagent> param)
		{
			_presentation.DeleteReagent(param.Parameter);
		}

		private void menuProductInsert_Click(object sender, EventArgs e)
		{
			Product product = Product.CreateProduct(default(int), string.Empty, string.Empty, string.Empty,
			                                        DateTime.Today.AddDays(1),
			                                        default(int));
			using (var dlg = new ProductDialog(new DialogParam<Product>(ActionTypes.Insert, product), InsertProduct))
				dlg.ShowDialog();
		}

		private void ctxmenuProductInsert_Click(object sender, EventArgs e)
		{
			var reagent = GetSelectedObjectTag(ctxmenuReagent) as Reagent;
			if (reagent == null)
				return;

			Product product = Product.CreateProduct(default(int), string.Empty, string.Empty, string.Empty,
			                                        DateTime.Today.AddDays(1),
			                                        reagent.ReagentID);
			using (var dlg = new ProductDialog(new DialogParam<Product>(ActionTypes.Insert, product), InsertProduct))
				dlg.ShowDialog();
		}

		private void InsertProduct(DialogParam<Product> param)
		{
			_presentation.InsertProduct(param.Parameter);
		}

		private void ctxmenuProductUpdate_Click(object sender, EventArgs e)
		{
			var product = GetSelectedObjectTag(ctxmenuProduct) as Product;
			if (product == null)
				return;

			using (var dlg = new ProductDialog(new DialogParam<Product>(ActionTypes.Update, product), UpdateProduct))
				dlg.ShowDialog();
		}

		private void menuProductUpdate_Click(object sender, EventArgs e)
		{
			var product = GetSelectedObjectTag(listviewProduct) as Product;
			if (product == null)
				return;

			using (var dlg = new ProductDialog(new DialogParam<Product>(ActionTypes.Update, product), UpdateProduct))
				dlg.ShowDialog();
		}

		private void UpdateProduct(DialogParam<Product> param)
		{
			_presentation.UpdateProduct(param.Parameter);
		}

		private void menuProductDelete_Click(object sender, EventArgs e)
		{
			var product = GetSelectedObjectTag(listviewProduct) as Product;
			if (product == null)
				return;

			using (var dlg = new ProductDialog(new DialogParam<Product>(ActionTypes.Delete, product), DeleteProduct))
				dlg.ShowDialog();
		}

		private void ctxmenuProductDelete_Click(object sender, EventArgs e)
		{
			var product = GetSelectedObjectTag(ctxmenuProduct) as Product;
			if (product == null)
				return;

			using (var dlg = new ProductDialog(new DialogParam<Product>(ActionTypes.Delete, product), DeleteProduct))
				dlg.ShowDialog();
		}

		private void DeleteProduct(DialogParam<Product> param)
		{
			_presentation.DeleteProduct(param.Parameter);
		}

		private void menuRecordDelete_Click(object sender, EventArgs e)
		{
			var record = GetSelectedObjectTag(listviewRecord) as Record;
			DeleteRecord(record);
		}

		private void ctxmenuRecordDelete_Click(object sender, EventArgs e)
		{
			var record = GetSelectedObjectTag(ctxmenuRecord) as Record;
			DeleteRecord(record);
		}

		private void DeleteRecord(Record record)
		{
			if (record == null)
			{
				MessageBox.Show("请选择一条要删除的记录。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Stop);
				return;
			}

			DialogResult confirm = MessageBox.Show("确认删除当前选中的记录吗？", "确认删除", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
			if (confirm == DialogResult.Yes)
				_presentation.DeleteRecord(record);
		}

		private void ctxmenuIncomingInsert_Click(object sender, EventArgs e)
		{
			var product = GetSelectedObjectTag(listviewProduct) as Product;
			if (product == null)
				return;

			IncomingRecord record = IncomingRecord.CreateIncomingRecord(0, DateTime.Now, 1, product.ProductID, string.Empty);
			using (var dlg = new RecordDialog(new DialogParam<Record>(ActionTypes.Insert, record), InsertRecord))
				dlg.ShowDialog();
		}

		private void ctxmenuOutgoingInsert_Click(object sender, EventArgs e)
		{
			var product = GetSelectedObjectTag(listviewProduct) as Product;
			if (product == null)
				return;

			OutgoingRecord record = OutgoingRecord.CreateOutgoingRecord(0, DateTime.Now, 1, product.ProductID, string.Empty);
			using (var dlg = new RecordDialog(new DialogParam<Record>(ActionTypes.Insert, record), InsertRecord))
				dlg.ShowDialog();
		}

		private void ctxmenuWearInsert_Click(object sender, EventArgs e)
		{
			var product = GetSelectedObjectTag(listviewProduct) as Product;
			if (product == null)
				return;

			WearRecord record = WearRecord.CreateWearRecord(0, DateTime.Now, 1, product.ProductID, string.Empty);
			using (var dlg = new RecordDialog(new DialogParam<Record>(ActionTypes.Insert, record), InsertRecord))
				dlg.ShowDialog();
		}

		private void InsertRecord(DialogParam<Record> param)
		{
			Record record = param.Parameter;
			if (record == null)
				return;

			_presentation.InsertRecord(record);
		}

		private void toolIncoming_Click(object sender, EventArgs e)
		{
			IncomingRecord record = IncomingRecord.CreateIncomingRecord(0, DateTime.Now, 1, 0, string.Empty);
			using (var dlg = new RecordDialog(new DialogParam<Record>(ActionTypes.Insert, record), InsertRecord))
				dlg.ShowDialog();
		}

		private void toolOutgoing_Click(object sender, EventArgs e)
		{
			OutgoingRecord record = OutgoingRecord.CreateOutgoingRecord(0, DateTime.Now, 1, 0, string.Empty);
			using (var dlg = new RecordDialog(new DialogParam<Record>(ActionTypes.Insert, record), InsertRecord))
				dlg.ShowDialog();
		}

		private void toolWear_Click(object sender, EventArgs e)
		{
			WearRecord record = WearRecord.CreateWearRecord(0, DateTime.Now, 1, 0, string.Empty);
			using (var dlg = new RecordDialog(new DialogParam<Record>(ActionTypes.Insert, record), InsertRecord))
				dlg.ShowDialog();
		}

		private void menuRecordInsert_Click(object sender, EventArgs e)
		{
			using (var dlg = new RecordDialog(new DialogParam<Record>(ActionTypes.Insert, null), InsertRecord))
				dlg.ShowDialog();
		}

		private void toolStock_Click(object sender, EventArgs e)
		{
			using (var dlg = new ReportForm(ReportTypes.Stock, Settings.Default.Company))
				dlg.ShowDialog();
		}

		private void toolRecord_Click(object sender, EventArgs e)
		{
			using (var dlg = new ReportForm(ReportTypes.Record, Settings.Default.Company))
				dlg.ShowDialog();
		}

		private void toolPurchase_Click(object sender, EventArgs e)
		{
			using (var dlg = new ReportForm(ReportTypes.Purchase, Settings.Default.Company))
				dlg.ShowDialog();
		}

		private void toolExpiration_Click(object sender, EventArgs e)
		{
			using (var dlg = new ReportForm(ReportTypes.Expiration, Settings.Default.Company))
				dlg.ShowDialog();
		}

		private void menuPrintPurchase_Click(object sender, EventArgs e)
		{
			toolPurchase_Click(sender, e);
		}

		private void menuPrintExpiration_Click(object sender, EventArgs e)
		{
			toolExpiration_Click(sender, e);
		}

		private void menuPrintStock_Click(object sender, EventArgs e)
		{
			toolStock_Click(sender, e);
		}

		private void menuPrintRecord_Click(object sender, EventArgs e)
		{
			toolRecord_Click(sender, e);
		}

		private void menuCompany_Click(object sender, EventArgs e)
		{
			using (var dlg = new UserForm())
				dlg.ShowDialog();
		}

		private void menuAccount_Click(object sender, EventArgs e)
		{
			using (var dlg = new AccountForm())
				dlg.ShowDialog();
		}

		private void menuBackup_Click(object sender, EventArgs e)
		{
			using (var dlg = new SaveFileDialog())
			{
				dlg.OverwritePrompt = true;
				dlg.DefaultExt = "bak";
				dlg.Filter = "SQL Server Backup files (*.bak)|*.bak|所有文件 (*.*)|*.*";

				if (dlg.ShowDialog(this) == DialogResult.OK)
					try
					{
						DataMaintain.Backup(dlg.FileName);
						string msg = string.Format("数据已成功备份至:\r\n  [{0}]", dlg.FileName);
						MessageBox.Show(msg, "数据备份", MessageBoxButtons.OK, MessageBoxIcon.Information);
					}
					catch (SqlException exp)
					{
						string msg = string.Format("数据备份失败:\r\n  [{0}]", exp.Message);
						MessageBox.Show(msg, "数据备份", MessageBoxButtons.OK, MessageBoxIcon.Error);
					}
			}
		}

		private void menuRestore_Click(object sender, EventArgs e)
		{
			DialogResult confirm = MessageBox.Show("数据恢复将导致当前数据被覆盖，确认吗？", "警告", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
			if (confirm != DialogResult.Yes)
				return;

			using (var dlg = new OpenFileDialog())
			{
				dlg.DefaultExt = "bak";
				dlg.Filter = "SQL Server Backup files (*.bak)|*.bak|所有文件 (*.*)|*.*";

				if (dlg.ShowDialog(this) == DialogResult.OK)
					try
					{
						DataMaintain.Restore(dlg.FileName);
						_presentation.RaiseEventWhenCatalogsUpdated();
						string msg = string.Format("数据已成功恢复:\r\n  [{0}]", dlg.FileName);
						MessageBox.Show(msg, "数据恢复", MessageBoxButtons.OK, MessageBoxIcon.Information);
					}
					catch (SqlException exp)
					{
						string msg = string.Format("数据恢复失败:\r\n  [{0}]", exp.Message);
						MessageBox.Show(msg, "数据恢复", MessageBoxButtons.OK, MessageBoxIcon.Error);
					}
			}
		}

		private void menuReset_Click(object sender, EventArgs e)
		{
			DialogResult confirm = MessageBox.Show("系统复位将导致所有数据被删除，确认吗？", "警告", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
			if (confirm != DialogResult.Yes)
				return;

			try
			{
				DataMaintain.Reset();
				_presentation.RaiseEventWhenCatalogsUpdated();
				MessageBox.Show("系统数据已全部清空复位", "系统复位", MessageBoxButtons.OK, MessageBoxIcon.Information);
			}
			catch (SqlException exp)
			{
				string msg = string.Format("系统复位失败:\r\n  [{0}]", exp.Message);
				MessageBox.Show(msg, "系统复位", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}

		private void MainForm_Shown(object sender, EventArgs e)
		{
			using (var dlg = new LogonForm(Logon))
			{
				dlg.ShowDialog();

				if (dlg.DialogResult != DialogResult.OK)
					Close();
				else
					new CheckStockForm().ShowDialog(this);
			}
		}

		private void Logon()
		{
			try
			{
				InitializeTreeRoot();
				InitializeEventProxy();

				_presentation.Initialize();
			}
			catch (EntityException e)
			{
				var result = MessageBox.Show("连接数据库失败，可能是因为系统未初始化。\r\n初始化系统数据库吗？", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Stop);
				if (result == DialogResult.Yes)
					menuReset_Click(this, new EventArgs());
				else
				{
					MessageBox.Show("程序遇到下列问题，即将退出。\r\n  " + e.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
					Close();
				}
			}
		}

		#region Event of Form

		private readonly TreeNode _nodeRoot = new TreeNode("试剂分类");

		private void ctxmenuCatalog_Opening(object sender, CancelEventArgs e)
		{
			var catalog = GetSelectedObjectTag(ctxmenuCatalog) as Catalog;
			if (catalog == null)
			{
				e.Cancel = true;
				return;
			}

			if (DefaultResources.DEFAULT_CATALOG_NAME.Equals(catalog.Name))
			{
				ctxmenuCatalogUpdate.Enabled = false;
				ctxmenuCatalogDelete.Enabled = false;
			}
			else
			{
				ctxmenuCatalogUpdate.Enabled = true;
				ctxmenuCatalogDelete.Enabled = true;
			}
		}

		private void ctxmenuProduct_Opening(object sender, CancelEventArgs e)
		{
			Point menu = listviewProduct.PointToClient(ctxmenuProduct.Location);
			ListViewItem item = listviewProduct.GetItemAt(menu.X, menu.Y);

			if (item == null)
				e.Cancel = true;
			else
			{
				Rectangle rect = item.GetBounds(ItemBoundsPortion.Entire);
				if ((menu.X < rect.X) || (menu.Y < rect.Y))
					e.Cancel = true;
			}
		}

		private void ctxmenuRecord_Opening(object sender, CancelEventArgs e)
		{
			ctxmenuRecordDelete.Enabled = listviewProduct.SelectedItems.Count > 0;

			Point menu = listviewRecord.PointToClient(ctxmenuRecord.Location);
			ListViewItem item = listviewRecord.GetItemAt(menu.X, menu.Y);

			if (item == null)
				e.Cancel = true;
			else
			{
				Rectangle rect = item.GetBounds(ItemBoundsPortion.Entire);
				if ((menu.X < rect.X) || (menu.Y < rect.Y))
					e.Cancel = true;
			}
		}

		public void BuildTreeViewCatalog(object sender, EntityEventArgs e)
		{
			treeviewCatalog.Nodes.Clear();
			_nodeRoot.Nodes.Clear();
			treeviewCatalog.Nodes.Add(_nodeRoot);

			var catalogs = e.Argument as IList<Catalog>;
			if (catalogs == null)
				return;
			if (catalogs.Count == 0)
				return;

			foreach (
				TreeNode nodeCatalog in
					catalogs.Select(catalog => new TreeNode(catalog.Name) {Tag = catalog, ContextMenuStrip = ctxmenuCatalog}))
				_nodeRoot.Nodes.Add(nodeCatalog);

			_nodeRoot.ExpandAll();
		}

		private void InsertReagentsIntoTreeView(object sender, EntityEventArgs e)
		{
			var reagents = e.Argument as IList<Reagent>;
			if (reagents == null)
				return;

			foreach (TreeNode nodeCatalog in _nodeRoot.Nodes)
			{
				var catalog = nodeCatalog.Tag as Catalog;
				if (catalog == null)
					break;

				nodeCatalog.Nodes.Clear();

				foreach (TreeNode nodeReagent in reagents.Where(r => r.CatalogID.Equals(catalog.CatalogID)).Select(
					reagent => new TreeNode(reagent.Name) {Tag = reagent, ContextMenuStrip = ctxmenuReagent}))
					nodeCatalog.Nodes.Add(nodeReagent);
			}
		}

		public void BuildLabelReagent(object sender, EntityEventArgs e)
		{
			labelReagent.ForeColor = SystemColors.ControlText;
			statusMain.ForeColor = SystemColors.ControlText;
			statusMain.BackColor = SystemColors.Control;
			labelReagent.Text = string.Empty;

			var reagent = e.Argument as Reagent;
			if (reagent == null)
			{
				return;
			}

			// {0}：目前库存{2}{1}。[ 常备量{3}{1}，报警量{4}{1}，提前{5}天失效报警 ]
			string description = string.Format(DefaultResources.REAGENT_DESCRIPTION_PATTERN,
			                                   reagent.Name,
			                                   reagent.Unit,
			                                   reagent.Quantity(),
			                                   reagent.StandingCount,
			                                   reagent.AlertCount,
			                                   reagent.AlertPeriod);

			ColorPairs colors = reagent.GetColorPairs();
			labelReagent.ForeColor = colors.ForeColor;
			statusMain.ForeColor = colors.ForeColor;
			statusMain.BackColor = colors.BackColor;
			labelReagent.Text = description;
		}

		private void BuildLabelProduct(object sender, EntityEventArgs e)
		{
			labelProduct.Text = string.Empty;
			labelProduct.BorderSides = ToolStripStatusLabelBorderSides.None;

			var product = e.Argument as Product;
			if (product == null)
			{
				return;
			}

			// {0}<{1}>：当前库存{2}{3}
			string description = string.Format(DefaultResources.PRODUCT_DESCRIPTION_PATTERN,
			                                   product.Manufacturer,
			                                   product.Batch,
			                                   product.Quantity(),
			                                   CurrentUnit());
			labelProduct.Text = description;
			labelProduct.BorderSides = ToolStripStatusLabelBorderSides.All;
		}

		private string CurrentUnit()
		{
			if (treeviewCatalog.SelectedNode == null)
				return string.Empty;

			var reagent = treeviewCatalog.SelectedNode.Tag as Reagent;
			return reagent == null ? string.Empty : reagent.Unit;
		}

		public void BuildListViewProduct(object sender, EntityEventArgs e)
		{
			listviewProduct.Items.Clear();

			var products = e.Argument as IList<Product>;
			if (products == null)
				return;

			// 厂商  规格  单位  批次  失效日期
			string unit = CurrentUnit();
			foreach (Product product in products)
			{
				var item = new ListViewItem(new[]
				                            	{
				                            		product.Manufacturer,
				                            		product.Specification,
				                            		unit,
				                            		product.Batch,
				                            		product.ExpirationDate.ToLocalTime().ToString("yyyy-MM-dd")
				                            	}) {Tag = product};

				ColorPairs colors = product.GetColorPairs();
				item.ForeColor = colors.ForeColor;
				item.BackColor = colors.BackColor;

				listviewProduct.Items.Add(item);
			}
		}

		public void BuildListViewRecord(object sender, EntityEventArgs e)
		{
			listviewRecord.Items.Clear();

			var records = e.Argument as IList<Record>;
			if (records == null)
				return;

			// 出入库  发生日期  数量(单位)  发票号  领用人  损耗原因
			string unit = CurrentUnit();
			foreach (Record record in records)
			{
				var subitems = new List<string>
				               	{
				               		record.Caption(),
				               		record.Date.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss"),
				               		record.Count.ToString() + unit
				               	};

				if (record is IncomingRecord)
					subitems.AddRange(new[] {((IncomingRecord) record).Bill, string.Empty, string.Empty});
				else if (record is OutgoingRecord)
					subitems.AddRange(new[] {string.Empty, ((OutgoingRecord) record).Recipient, string.Empty});
				else if (record is WearRecord)
					subitems.AddRange(new[] {string.Empty, string.Empty, ((WearRecord) record).Reason});

				listviewRecord.Items.Add(new ListViewItem(subitems.ToArray()) {Tag = record});
			}
		}

		private void treeviewCatalog_AfterSelect(object sender, TreeViewEventArgs e)
		{
			if (treeviewCatalog.SelectedNode == null)
				return;

			var reagent = treeviewCatalog.SelectedNode.Tag as Reagent;
			_presentation.RaiseEventWhenCurrentReagentChanged(reagent);
		}

		private void listviewProduct_SelectedIndexChanged(object sender, EventArgs e)
		{
			if (listviewProduct.SelectedItems.Count <= 0)
				return;

			var product = listviewProduct.SelectedItems[0].Tag as Product;
			_presentation.RaiseEventWhenCurrentProductChanged(product);
			BuildLabelProduct(sender, new EntityEventArgs(product));
		}

		#endregion

		#region Menu & Toolbutton

		private void toolExit_Click(object sender, EventArgs e)
		{
			menuExit_Click(sender, e);
		}

		private void menuExit_Click(object sender, EventArgs e)
		{
			Close();
		}

		#endregion
	}
}